#include "FirstPersonCamera.hpp"
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/euler_angles.hpp>

constexpr glm::vec4 FORWARD_VECTOR = glm::vec4(0, 0, 1, 0);
constexpr glm::vec4 RIGHT_VECTOR = glm::vec4(1, 0, 0, 0);
constexpr glm::vec4 UP_VECTOR = glm::vec4(0, 1, 0, 0);

using namespace Data;

void FirstPersonCamera::Reset() { m_pos = glm::vec3(0.0f, 0.0f, 7.0f); }

void FirstPersonCamera::MoveHelper(float d, glm::vec4 direction) {
  glm::mat4 rotaMatrix =
      glm::yawPitchRoll(glm::radians(m_yaw), glm::radians(m_pitch), 0.0f);
  glm::vec4 dir = rotaMatrix * direction;

  m_pos = glm::vec4(m_pos, 0) + dir * d;
}

void FirstPersonCamera::MoveLeftRight(float d) { MoveHelper(d, RIGHT_VECTOR); }

void FirstPersonCamera::MoveForwardBack(float d) { MoveHelper(d, FORWARD_VECTOR); }

void FirstPersonCamera::MoveUpDown(float d) { MoveHelper(d, UP_VECTOR); }

glm::vec4 FirstPersonCamera::GetUpVector() {
  glm::mat4 yawMatrix = glm::rotate(glm::mat4(1), m_yaw, glm::vec3(0, 1, 0));

  return yawMatrix * glm::vec4(0, 1, 0, 1);
}

glm::mat4 FirstPersonCamera::GetViewMatrix() {
  glm::mat4 rota = glm::yawPitchRoll(glm::radians(m_yaw), glm::radians(m_pitch), 0.0f);

  glm::vec4 target = rota * FORWARD_VECTOR;
  target = glm::vec4(m_pos, 0) - glm::normalize(target);

  glm::mat4 yawMatrix = glm::rotate(glm::mat4(1), m_yaw, glm::vec3(0, 1, 0));

  glm::vec4 right = yawMatrix * RIGHT_VECTOR;
  glm::vec4 up = yawMatrix * UP_VECTOR;
  glm::vec4 forward = yawMatrix * FORWARD_VECTOR;

  return glm::lookAt(m_pos, glm::vec3(target), glm::vec3(up));
}

glm::vec4 FirstPersonCamera::GetViewDirection() {
  glm::mat4 rota = glm::yawPitchRoll(glm::radians(m_yaw), glm::radians(m_pitch), 0.0f);

  glm::vec4 target = rota * FORWARD_VECTOR;
  target = glm::vec4(m_pos, 0) - glm::normalize(target);

  return target;
}